package com.zsj.juc.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zsj
 * @version 1.0
 * @date 2024/4/19 20:11
 * @description
 */
public class TicketTest {

    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        //三个线程模拟抢票  非公平锁
        new Thread(() -> {
            for (int i = 0; i < 55; i++) {
                ticket.sale();
            }
        }, "a").start();

        new Thread(() -> {
            for (int i = 0; i < 55; i++) {
                ticket.sale();
            }
        }, "b").start();

        new Thread(() -> {
            for (int i = 0; i < 55; i++) {
                ticket.sale();
            }
        }, "c").start();

        try {
            TimeUnit.MILLISECONDS.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("a:" + ticket.a);
        System.out.println("b:" + ticket.b);
        System.out.println("c:" + ticket.c);
    }

}


class Ticket {//资源类
    private int number = 50;
    //    ReentrantLock lock = new ReentrantLock();//可重入锁 但是非公平
    // 在非公平的情况下 会发生锁饥饿的情况 也就是某个线程可能一次都没有抢到锁
    /*
    在非公平的情况下 会将cpu利用的更充分
    使用多线程的重要考量点是线程切换的开销 当采用非公平锁时
    当1个线程请求锁获取同步状态 然后释放同步状态 所以刚释放的锁在此刻再次获取同步状态的概率就会变得非常大
    也就减少了线程的开销 避免了线程切换引来的cpu开销
        ** 《线程切换是利用了cpu中的时间片》

        面试题：
        什么时候用公平锁?什么时候用非公平锁?
        答: 如果是为了更高的吞吐量 很明显使用非公平锁是比较合理的 避免了线程之间的切换 吞吐量自然会比较高
        反之为了如果是为了线程之间的公平性更高的话？使用公平锁比较好 可以有效避免了线程饥饿的情况
     */
    ReentrantLock lock = new ReentrantLock(true);//可重入锁 公平

    //每个线程获取的次数
    volatile int a = 0, b = 0, c = 0;

    public void sale() {
        lock.lock();
        try {
            if (number > 0) {
                //卖票
                System.out.println(Thread.currentThread().getName()
                        + "卖出第" + (number--) + "票,还剩下" + number);
                if (Thread.currentThread().getName().equals("a")) a++;
                else if (Thread.currentThread().getName().equals("b")) b++;
                else c++;
            }
        } finally {
            lock.unlock();
        }
    }
}